<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>数据抽离与数据管理 | 被删的前端游乐场</title>
    <meta name="description" content="Just playing around">
    
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.a683ed26.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.e5cf4092.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.c853767c.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.eed49fdd.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/40.6498193b.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.a683ed26.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端基础</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端基础</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前端入门</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-0cd75e06><span class="stand" data-v-0cd75e06></span> <div class="cat" data-v-0cd75e06><div class="body" data-v-0cd75e06></div> <div class="head" data-v-0cd75e06><div class="ear" data-v-0cd75e06></div> <div class="ear" data-v-0cd75e06></div></div> <div class="face" data-v-0cd75e06><div class="nose" data-v-0cd75e06></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div></div> <div class="tail-container" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>前端深入理解</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-basic/understanding/build-application.html" class="sidebar-link">前端构建大型应用</a></li><li><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html" class="active sidebar-link">数据抽离与数据管理</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html#状态数据" class="sidebar-link">状态数据</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html#动态数据" class="sidebar-link">动态数据</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html#将数据与应用抽离" class="sidebar-link">将数据与应用抽离</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html#数据的流动" class="sidebar-link">数据的流动</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html#适度的管理" class="sidebar-link">适度的管理</a></li></ul></li><li><a href="/front-end-playground/front-end-basic/understanding/component-with-configuration.html" class="sidebar-link">组件配置化</a></li><li><a href="/front-end-playground/front-end-basic/understanding/component-with-itself.html" class="sidebar-link">一个组件的自我修养</a></li><li><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html" class="sidebar-link">页面区块化与应用组件化</a></li><li><a href="/front-end-playground/front-end-basic/understanding/template-engine.html" class="sidebar-link">前端模板引擎</a></li><li><a href="/front-end-playground/front-end-basic/understanding/dialogue-abstraction.html" class="sidebar-link">对话抽象</a></li><li><a href="/front-end-playground/front-end-basic/understanding/data-driven-or-event-driven.html" class="sidebar-link">前端思维转变--从事件驱动到数据驱动</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>托目前主流框架的福，我们能从事件驱动脱离，来到了数据驱动的世界，可以参考以前的<a href="/front-end-playground/front-end-basic/understanding/data-driven-or-event-driven.html">《前端思维转变--从事件驱动到数据驱动》</a>。在常常与数据打交道后，我们对组件的封装、配置化的思想一步步地深入和拓展之后，对于数据和状态的管理，也慢慢地出现了一些思考。</p> <h1 id="应用数据抽离"><a href="#应用数据抽离" aria-hidden="true" class="header-anchor">#</a> 应用数据抽离</h1> <p>在把数据与逻辑分离到极致的时候，你再看一个应用，会看到一具静态的逻辑躯壳，以及数据如灵魂般地注入到应用里，使其获得生命。</p> <p>数据的抽离，其实与配置化的思想有想通的地方，即把可变部分分离，然后通过注入的方式，来实现具体的功能和展示。</p> <h2 id="状态数据"><a href="#状态数据" aria-hidden="true" class="header-anchor">#</a> 状态数据</h2> <p>在一个应用的设计里，我们可能会拥有多个模块，每个模块又各自维护着自己的某些状态，同时部分状态相互影响着，最终呈现出应用的整体状态。</p> <p>这些状态，都可以通过数据的方式来表示，我们简单称之为状态数据。</p> <p>怎么定义状态数据？最浅显的办法就是这些数据，可以直接影响模块的状态，如对话框的出现、隐藏，标签的激活、失活，长流程的当前步骤等，都可以作为状态数据。用在 Vue 里面，可能常见如 <code>v-show</code>、<code>v-if</code>、以及其他状态判断逻辑。</p> <p>我们的应用，大多数都是呈现树状结构，一层层地往下分解，直到无法分割的某个简单功能。同时，我们的组件也会呈现出来这样树状的方式，状态是跟随着组件维护，某个功能状态属于组件自己，最外层的状态则属于整个应用，当然这个应用也是组件的一种表示方式。</p> <p>因此，我们的状态数据，也呈现一种树状的方式，与我们的组件相对应。就像 CSS 与 DOM 节点。</p> <h2 id="动态数据"><a href="#动态数据" aria-hidden="true" class="header-anchor">#</a> 动态数据</h2> <p>我们还有很多的数据，如内容、个人信息等，都是需要我们从数据库拉取回来的。这种需要动态获取然后展示或是影响配置的一些数据，我们称之为动态数据。</p> <p>动态数据不同于状态数据，并不会跟随着应用的生命周期而改变，也不会随着应用的关闭而消失。它们独立存在于外界，通过注入的方式进入应用，并影响具体的展示和功能逻辑。</p> <p>和状态数据不一样，动态数据并不一定呈现为树状的形式。它可以是并行的，可以是联动关系，但是随着注入的地方不一样，最终在应用中形成的结构也会不一致。我们可以简单理解为每个动态数据都是平等的。</p> <h2 id="将数据与应用抽离"><a href="#将数据与应用抽离" aria-hidden="true" class="header-anchor">#</a> 将数据与应用抽离</h2> <p>要怎么理解将数据与应用抽离呢？形象点形容，就像是我们一个公司，所有的桌子椅子装修和电脑都是静态的，它们相当于一个个的组件，同时每个办公室也可以是一个大点的组件或是模块。</p> <p>那么在我们这个公司里：</p> <ul><li>状态数据：椅子的位置、消耗的电量、办公室的照明和空调状态等</li> <li>动态数据：员工等各种人员流动</li></ul> <p>当然，公司里没有人员流动的时候，似乎就是个空壳。每天上班的时候，一个个的程序员就涌入公司，给公司注入灵魂，公司得以运作。</p> <p>要说将数据和应用抽离，作用到这里大概是这个样子？</p> <div class="language-cmd extra-class"><pre class="language-text"><code>--------------------------------------------------------
                         公司
---------------------------  ---------------------------
|                         |  |  人           人        |
|                         |  |       人          人    |
|         办公楼          |  |           人            |
|                         |  |    人     人     人  人 |
|                         |  |      人      人   人    |
---------------------------  ---------------------------
</code></pre></div><p>在公司正常运作的时候，则是这样的：</p> <div class="language-cmd extra-class"><pre class="language-text"><code>--------------------------------------------------------
                         公司
--------------------------------------------------------
|   人     人             人   人       人     人 人    |
|           人            人   人     人          人    |
|        人    人    办公楼   人   人          人       |
|     人    人                人  人     人     人  人  |
|     人     人         人      人     人      人   人  |
--------------------------------------------------------
</code></pre></div><p>当然，人不只是站在办公楼里面这么简单，更多的，人会与各种物件进行交互和交流，人与人之间也会相互影响。但是这样简单的管理，很容易造成公司的混乱，所以我们会把人员有规律有组织地分别注入到每个办公室、隔间里面。</p> <p>这就是我们要做的，不只是如何划分数据、将数据与应用抽离，我们还需要将其有规律地管理。所以，这大概是我们接下来的要讲的内容。</p> <h1 id="应用数据管理"><a href="#应用数据管理" aria-hidden="true" class="header-anchor">#</a> 应用数据管理</h1> <p>我们知道哪些数据需要抽离、如何将数据抽离出来，同时，我们还需要知道，这些数据在抽离出来之后，该怎么去进行管理。</p> <h2 id="数据的流动"><a href="#数据的流动" aria-hidden="true" class="header-anchor">#</a> 数据的流动</h2> <p>数据在注入到我们的应用中后，并不只是简单地存在。它可能会影响应用的状态、同时也会影响其他同样注入的数据。</p> <p>数据与数据之间的交互，其实在某方面相等于我们组件之间的通信，包括但不限于以下的一些方式：</p> <ul><li>事件通知</li> <li>共享对象</li> <li>单方向流动</li></ul> <h3 id="事件通知"><a href="#事件通知" aria-hidden="true" class="header-anchor">#</a> 事件通知</h3> <p>事件的监听和触发机制，在许多的场景下都能适用，如浏览器点击、输入框的输入操作，则是典型的事件机制。而在很多时候，我们也可以通过事件通知的方式，来进行数据间的交互，如 Websocket 机制。</p> <p>事件通知机制很方便，可以随意地定义触发的时机，也可以任意地点使用监听或是触发。</p> <p>但事件机制的弊端也是很明显，就是每一个事件的触发对应一个监听，关系是一一对应。在整个应用中看，则是散落在各处，随意乱窜的数据流动。需要定位的时候，只能通过全局搜索的方式来跟踪数据的去向。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524236289%281%29.jpg" alt="image"></p> <p>当然，也有些人会定义一个中转站，所有的事件数据流都会经过那，这样的维护方式会有所改善。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524236465%281%29.jpg" alt="imgae"></p> <p>类似这种，额，可能会好一些？</p> <h3 id="共享对象"><a href="#共享对象" aria-hidden="true" class="header-anchor">#</a> 共享对象</h3> <p>共享对象是很简答的一种方式，当我们需要多个地方使用相同的数据，我们就把它们放置在一个地方，大家都去那理获取和更新。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524236687%281%29.jpg" alt="image">
(额请叫我灵魂画家)</p> <p>通过注入对象的引用，来在不同组件中获取相同的数据源。当然这样的使用方式，需要考虑锁的问题（当然单线程的 JS 里面这样的情况比较少）。</p> <p>同时，很多时候我们在定义一个对象，有时候想要某些地方共享，有时候又想要获取一个全新独立的对象。这种情况下，我们需要考虑怎样去维护一套这种数据与实例。</p> <h3 id="单方向流动"><a href="#单方向流动" aria-hidden="true" class="header-anchor">#</a> 单方向流动</h3> <p>给数据的流动一个方向，则可以方便地跟踪数据的来源和去处。通过流的方式管理状态，常见的状态管理工具 Vuex、Redux 等，都是这样的方式去管理。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524237398.jpg" alt="image"></p> <p>当然，赋予数据流方向，但是数据的存放呢，可以通过共享对象的方式，也可以维护一个数据中心，所有的数据变更方式、触发逻辑、影响范围，都在数据中心里面管理和维护。</p> <h3 id="树状作用域"><a href="#树状作用域" aria-hidden="true" class="header-anchor">#</a> 树状作用域</h3> <p>很多时候，我们的应用通过一层层地封装和隔离，最终会呈现为树状。</p> <p>我们可以根据组件的树状作用域，结合共享对象的管理，来注入树状的数据结构。典型如 Angular 里，则是通过提供通用的依赖注入方式，配合树状的模块管理，可通过局部注入实例来获取共享或是隔离的数据。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524238569%281%29.jpg" alt="image"></p> <h2 id="适度的管理"><a href="#适度的管理" aria-hidden="true" class="header-anchor">#</a> 适度的管理</h2> <p>与组件的封装和配置化相似，数据的抽象、抽离，也是需要适度的。</p> <p>当我们的应用很小，只有简单的功能的时候，我们甚至不需要对这些状态、数据什么的进行特殊的管理，甚至一个简单的变量就可以搞定了。随着应用组件数量变多，我们开始有了组件的作用域，当组件需要通信，我们可以通过简单的事件机制、或是共享对象的方式来进行交互。</p> <p>当我们的项目越做越大，要在上百的状态、上万的数据里要按照想要的方式去展示我们的应用，这时候一个状态管理工具则可以轻松解决乱糟糟的数据流问题。</p> <h1 id="结束语"><a href="#结束语" aria-hidden="true" class="header-anchor">#</a> 结束语</h1> <p>对数据的抽离和管理，也越来越成为我们在项目架构中需要考虑的部分。应用状态数据的管理，其实里面会有很多的设计模式。或许这块过于抽象，这篇文章也未能表达出最好的想法。但是对于设计模式，我们可以先了解下，在实战的时候，你会不自觉地想起来，啊原来这就是哪个设计模式的使用场景呀~</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-basic/understanding/component-communication-with-data-model.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-basic/understanding/build-application.html" class="prev">
          前端构建大型应用
        </a></span> <span class="next"><a href="/front-end-playground/front-end-basic/understanding/component-with-configuration.html">
          组件配置化
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-7962" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty0.svg);"></div></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.e5cf4092.js" defer></script><script src="/front-end-playground/assets/js/3.c853767c.js" defer></script><script src="/front-end-playground/assets/js/2.eed49fdd.js" defer></script><script src="/front-end-playground/assets/js/40.6498193b.js" defer></script>
  </body>
</html>
